import {PopupManager} from 'element-ui/src/utils/popup';

import {createPopper} from '@popperjs/core';

const stop = e => e.stopPropagation();

/**
 * @param {HTMLElement} [reference=$refs.reference] - The reference element used to position the popper.
 * @param {HTMLElement} [popper=$refs.popper] - The HTML element used as popper, or a configuration used to generate the popper.
 * @param {String} [placement=button] - Placement of the popper accepted values: top(-start, -end), right(-start, -end), bottom(-start, -end), left(-start, -end)
 * @param {Number} [offset=0] - Amount of pixels the popper will be shifted (can be negative).
 * @param {Boolean} [visible=false] Visibility of the popup element.
 * @param {Boolean} [visible-arrow=false] Visibility of the arrow, no style.
 */
export default {
    props: {
        transformOrigin: {
            type: [Boolean, String],
            default: true
        },
        placement: {
            type: String,
            default: 'bottom'
        },
        boundariesPadding: {
            type: Number,
            default: 5
        },
        reference: {},
        popper: {},
        offset: {
            default: 0
        },
        value: Boolean,
        visibleArrow: Boolean,
        arrowOffset: {
            type: Number,
            default: 35
        },
        appendToBody: {
            type: Boolean,
            default: true
        },
        popperOptions: {
            type: Object,
            default() {
                return {
                    gpuAcceleration: false
                };
            }
        }
    },

    data() {
        return {
            showPopper: false,
            currentPlacement: ''
        };
    },

    watch: {
        value: {
            immediate: true,
            handler(val) {
                this.showPopper = val;
                this.$emit('input', val);
            }
        },

        showPopper(val) {
            if (this.disabled) return;
            val ? this.updatePopper() : this.destroyPopper();
            this.$emit('input', val);
        }
    },

    methods: {
        createPopper() {
            const that = this;
            if (this.$isServer) return;
            this.currentPlacement = this.currentPlacement || this.placement;
            if (!/^(top|bottom|left|right)(-start|-end)?$/g.test(this.currentPlacement)) {
                return;
            }

            const options = this.popperOptions;
            const popper = this.popperElm = this.popperElm || this.popper || this.$refs.popper;
            let reference = this.referenceElm = this.referenceElm || this.reference || this.$refs.reference;

            if (!reference &&
                this.$slots.reference &&
                this.$slots.reference[0]) {
                reference = this.referenceElm = this.$slots.reference[0].elm;
            }

            if (!popper || !reference) return;
            if (this.visibleArrow) this.appendArrow(popper);
            if (this.appendToBody) document.body.appendChild(this.popperElm);
            if (this.popperJS && this.popperJS.destroy) {
                this.popperJS.destroy();
            }

            options.placement = this.currentPlacement;
            options.offset = this.offset;
            options.arrowOffset = this.arrowOffset;
            if (!Array.isArray(options.modifiers)) options.modifiers = [];
            if (typeof options.onUpdate === 'function') {
                const onUpdate = {
                    name: 'onUpdate',
                    enabled: true,
                    phase: 'afterWrite',
                    fn: options.onUpdate,
                }
                options.modifiers.push(onUpdate)
            }
            options.modifiers.push(that.getZIndexStyles())

            this.popperJS = createPopper(reference, popper, {
                ...options,
                onFirstUpdate: _ => {
                    that.$emit('created', this);
                    that.resetTransformOrigin();
                    that.$nextTick(that.updatePopper);
                },
            });
            // debugger
            // this.popperJS.onFirstUpdate(_ => {
            //     this.$emit('created', this);
            //     this.resetTransformOrigin();
            //     this.$nextTick(this.updatePopper);
            // });
            // if (typeof options.onUpdate === 'function') {
            //     this.popperJS.onUpdate(options.onUpdate);
            // }
            this.popperElm.addEventListener('click', stop);
        },

        getZIndexStyles() {
            return {
                name: 'zIndexStyles',
                phase: 'write',
                enabled: true,
                options: {
                    zIndex: PopupManager.nextZIndex()
                },
            }
        },

        updatePopper() {
            const popperJS = this.popperJS;
            if (popperJS) {
                popperJS.setOptions({
                    modifiers: [
                        this.getZIndexStyles()
                    ]
                });
            } else {
                this.createPopper();
            }
        },

        doDestroy(forceDestroy) {
            /* istanbul ignore if */
            if (!this.popperJS || (this.showPopper && !forceDestroy)) return;
            this.popperJS.destroy();
            this.popperJS = null;
        },

        destroyPopper() {
            if (this.popperJS) {
                this.resetTransformOrigin();
            }
        },

        resetTransformOrigin() {
            if (!this.transformOrigin) return;
            let placementMap = {
                top: 'bottom',
                bottom: 'top',
                left: 'right',
                right: 'left'
            };
            // debugger
            const placement = this.popperJS.state.attributes.popper['data-popper-placement'];
            const origin = placementMap[placement];
            const transformOrigin = typeof this.transformOrigin === 'string'
                ? this.transformOrigin
                : ['top', 'bottom'].indexOf(placement) > -1 ? `center ${origin}` : `${origin} center`;
            // const options =
            this.popperJS.setOptions({
                modifiers: [
                    {
                        name: 'transformOrigin',
                        phase: 'write',
                        enabled: true,
                        options: {
                            transformOrigin: transformOrigin
                        },
                    }
                ]
            });
        },

        appendArrow(element) {
            let hash;
            if (this.appended) {
                return;
            }
            this.appended = true;

            for (let item in element.attributes) {
                if (/^_v-/.test(element.attributes[item].name)) {
                    hash = element.attributes[item].name;
                    break;
                }
            }

            const arrow = document.createElement('div');

            if (hash) {
                arrow.setAttribute(hash, '');
            }
            arrow.setAttribute('data-popper-arrow', '');
            arrow.className = 'popper__arrow';
            element.appendChild(arrow);
        }
    },

    beforeDestroy() {
        this.doDestroy(true);
        if (this.popperElm && this.popperElm.parentNode === document.body) {
            this.popperElm.removeEventListener('click', stop);
            document.body.removeChild(this.popperElm);
        }
    },

    // call destroy in keep-alive mode
    deactivated() {
        this.$options.beforeDestroy[0].call(this);
    }
};
